home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / repaint.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  27KB  |  1,108 lines

  1. /*
  2.  * $Id: repaint.c,v 0.91 1994/02/20 00:52:59 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * Handles all redraw events, including window resizing, re-positioning.
  26.  * For redraws not resulting from window resizing etc, program
  27.  * works nicely (might be faster than double buffer and does not
  28.  * look too bad) because it simulates "backing store" and "SaveUnder"
  29.  * by accumulating dirty rectangles and handle these dirty rectangles
  30.  * by repainting the  minimum region that need to be repainted.
  31.  *
  32.  * Multi-window redraws are also handled here via installed handler.
  33.  *
  34.  * To facilitate efficient redraw, a wrapper for FORMS library is used
  35.  * to (a). Get all dirty rectangles when a form is closed and (b)
  36.  * get all valid window IDs, which are used by cursor routines.
  37.  *
  38.  */
  39.  
  40. #if !defined(lint) && defined(F_ID)
  41. char *id_rpt = "$Id: repaint.c,v 0.91 1994/02/20 00:52:59 zhao Pre-Release $";
  42. #endif
  43.  
  44. #include "bit.h"
  45. #include <stdlib.h>        /* for exit */
  46. #include "extern.h"
  47.  
  48. /***************************************************************
  49.  * Handle window manager redraw events besides repaint screen. This
  50.  * is necessary because a window can be resized and repositioned
  51.  * while doing something that depends on the geometry. The wm_handler
  52.  * routine is called to handle this situation
  53.  *
  54.  * WM_handler takes a (IPTR, int) pair and it is launched
  55.  * with the second parameter having a value of 1
  56.  ***************************************************************/
  57.  
  58. #define MAXWMH   3
  59. static WMhandler wm_handler[MAXWMH];
  60.  
  61. /******************************************************
  62.  * Install a handler
  63.  *****************************************************/
  64. void
  65. install_wm_handler(WMhandler wm)
  66. {
  67.     register WMhandler *wmi = wm_handler, *wmf;
  68.  
  69.     /* search for an empty slot */
  70.     for (wmf = wmi + MAXWMH; wmi < wmf && *wmi && *wmi != wm; wmi++)
  71.     ;
  72.  
  73.     if (wmi == wmf)
  74.       {                /* overflew */
  75.       Bark("WMhandler", "Can't install--out of bounds");
  76.       return;
  77.       }
  78.     *wmi = wm;
  79. }
  80.  
  81. /******************************************************
  82.  * remove a handler
  83.  *******************************************************/
  84. void
  85. remove_wm_handler(WMhandler wm)
  86. {
  87.     register WMhandler *wmi = wm_handler, *wmf;
  88.  
  89.     for (wmf = wmi + MAXWMH; --wmf >= wmi && *wmf != wm;)
  90.     ;
  91.     if (wmf < wmi)
  92.       {
  93.       M_warn("WMhandler", "Can't uninstall--no such handler");
  94.       return;
  95.       }
  96.     *wmf = 0;
  97. }
  98.  
  99. /********************************************************
  100.  * checking currently installed handlers for debugging
  101.  *********************************************************/
  102. int
  103. total_wm_handler(void)
  104. {
  105.     register WMhandler *wmi = wm_handler, *wmf;
  106.     register int i = 0;
  107.  
  108.     for (wmf = wmi + MAXWMH; wmi < wmf; wmi++)
  109.     if (*wmi)
  110.         ++i;
  111.     return i;
  112. }
  113.  
  114. /***********************************************************
  115.  * Actually handling the events by calling installed handlers
  116.  ************************************************************/
  117. void
  118. handle_wm_other(IPTR im)
  119. {
  120.     register WMhandler *wmi = wm_handler, *wmf;
  121.  
  122.     /* last installed gets serviced first */
  123.     for (wmf = wmi + MAXWMH; --wmf >= wmi;)
  124.     if (*wmf)
  125.         (*wmf) (im, 1);
  126. }
  127.  
  128. /***************************************************************
  129.  * In some cases, bit has multiple windows open (excludng form windows),
  130.  * redraws for all windows other than the main window is handled
  131.  * via installed handlers wmuti_w_handler
  132.  *
  133.  * All multi-window redraw handlers take (IPTR, long) as their
  134.  * parameters. the second parameter is the window ID.
  135.  ***************************************************************/
  136.  
  137. #define MAXMULTIW  2        /* number of windows in addtion to main */
  138. static MWhandler mw_handler[MAXMULTIW];
  139.  
  140. /************************************************************
  141.  * Install a multi-window redraw handler
  142.  ***********************************************************/
  143. void
  144. install_multiw_handler(MWhandler mw)
  145. {
  146.     MWhandler *mwi = mw_handler, *mwf;
  147.  
  148.     for (mwf = mwi + MAXMULTIW; mwi < mwf && *mwi && *mwi != mw; mwi++)
  149.     ;
  150.     if (mwi != mwf)
  151.     *mwi = mw;
  152. }
  153.  
  154. /************************************************************
  155.  * Remove a multi-window redraw handler
  156.  ***********************************************************/
  157. void
  158. remove_multiw_handler(MWhandler handle)
  159. {
  160.     MWhandler *mwi = mw_handler, *mwf;
  161.  
  162.     for (mwf = mwi + MAXMULTIW; mwi < mwf && *mwi != handle; mwi++)
  163.     ;
  164.     if (mwi == mwf)
  165.       {
  166.       Bark("RM_multiw_h", "non exisitent handler");
  167.       }
  168.     *mwi = 0;
  169. }
  170.  
  171. /*************************************************************
  172.  * handle it
  173.  ************************************************************/
  174. static void
  175. handle_multiw(IPTR im, int win)
  176. {
  177.     MWhandler *mwi = mw_handler, *mwf;
  178.  
  179.     for (mwf = mwi + MAXMULTIW; --mwf >= mwi;)
  180.     if (*mwf)
  181.         (*mwf) (im, win);
  182. }
  183.  
  184.  
  185. /*********************************************************************
  186.  * Dirty rectangle routines
  187.  *
  188.  * A dirty rectangle specifies the region that needs to be redrawn.
  189.  ********************************************************************/
  190.  
  191. #define MAXDRECT 4        /* max. dirty rectangles  */
  192.  
  193. static int ndrect;
  194. static Rect_t drect[MAXDRECT];
  195. static int overlap(int, int, int, int);
  196.  
  197. /******************************************************************
  198.  * Add a region to the list that needs to be redrawn. Ignore it
  199.  * if not overlap with main window
  200.  *****************************************************************/
  201. void
  202. add_d_rect(int x, int y, int w, int h)
  203. {
  204.     register Rect_t *dr = drect + ndrect;
  205.  
  206.     /* add this rectangle only if overlaps with the main window */
  207.     if (overlap(x, y, w, h))
  208.       {
  209.       dr->x = x;
  210.       dr->y = y;
  211.       dr->w = w;
  212.       dr->h = h;
  213.  
  214.       /*
  215.        * if something is not handled correctly, i.e., ndrect out of
  216.        * bounds, better to a complete redraw by setting ndrect = 0
  217.        */
  218.       if (++ndrect >= MAXDRECT)
  219.         {
  220.         M_info("Drect", "recoverable %s", outbound);
  221.         ndrect = 0;
  222.         }
  223.       }
  224. }
  225.  
  226.  
  227. /**************************************************************
  228.  * When main window is resized, remap
  229.  *************************************************************/
  230.  
  231. static void
  232. remap_main_window(void)
  233. {
  234.     set_current_window(win_id);
  235.     reshapeviewport();
  236.     getorigin(&win_xo, &win_yo);
  237.     getsize(&win_w, &win_h);
  238.     reshapeviewport();
  239.     ortho2(-0.5, win_w - 0.5, -0.5, win_h - 0.5);
  240. }
  241.  
  242. void gather_dirty_region(void);
  243.  
  244. /**********************************************************************
  245.  * repaint the area that got messed up. Absolutely the minimum region that
  246.  * needs to be repainted.
  247.  **********************************************************************/
  248. static void
  249. do_redraw(IPTR im)
  250. {
  251.     int x, y, col;
  252.  
  253.     gather_dirty_region();
  254.  
  255.     if (!im->ok)
  256.       {
  257.       clear_screen(win_id, 0);
  258.       return;
  259.       }
  260.  
  261.  
  262.  
  263.     if (ndrect <= 0)
  264.       {
  265.       center_image(im, 2);
  266.  
  267.       display_image(im, -1, 1);
  268.  
  269.       /*
  270.        * service this request. Note it must come after centering because
  271.        * wm_other expects current im->{xi,yi} and it must come before
  272.        * displaying text and sgf
  273.        */
  274.  
  275.       handle_wm_other(im);
  276.       }
  277.     else
  278.       {                /* the stuff is from known regions */
  279.       Rect_t *dr = drect + ndrect;
  280.  
  281.       M_info("Repaint", "ndrect=%d", ndrect);
  282.  
  283.       while (--dr >= drect)
  284.         {
  285.         /* to window coordinates */
  286.         x = dr->x - win_xo;
  287.         y = dr->y - win_yo;
  288.         img_rect_redraw(im, x, y, dr->w, dr->h);
  289.         }
  290.  
  291.       }
  292.  
  293.     if (im->io->display != display_image)
  294.       {
  295.       display_text(im);
  296.       display_sgf(im);
  297.       }
  298.  
  299. }
  300.  
  301. /*****************************************************************
  302.  * Compress REDRAW events
  303.  * Can't be reliably done in GL
  304.  ***************************************************************/
  305. static void
  306. compress_redraw(int win)
  307. {
  308. #if 0                /* {* */
  309.     long dev = 0;
  310.     short val = 0;
  311.  
  312.     /*
  313.      * do redraw compression: The fact that qtest does not return val
  314.      * indicates a design flaw in GL. redraw compression can't be done
  315.      * reliably
  316.      */
  317.  
  318.     while (fl_qtest() == REDRAW && val == win)
  319.     dev = fl_qread(&val);
  320.  
  321.     if (val != win && dev == REDRAW)
  322.     fl_qenter(dev, val);
  323.     return;
  324. #endif /* } */
  325. }
  326.  
  327. /************************************************************************
  328.  * when REDRAW event is received, this routine is called. Need to take
  329.  * care the case where window size changes
  330.  ************************************************************************/
  331. void
  332. repaint(IPTR im, int win)
  333. {
  334.     long owin = winget();
  335.     short val = win;
  336.     long rwin;
  337.     int col;
  338.  
  339.     if (win <= 0)
  340.     return;
  341.  
  342.     compress_redraw(win);
  343.  
  344.     /* redraw request reason unknown. Must appear before handle_multiw */
  345.     if (ndrect <= 0)
  346.       {                /* from unknown region */
  347.       remap_main_window();
  348.       clear_over_pup();
  349.       drawmode(NORMALDRAW);
  350.       remap_main_window();
  351.       }
  352.  
  353.     /*
  354.      * if the request does not apply to main window, try one of the installed
  355.      * handlers
  356.      */
  357.     if (win != win_id)
  358.       {
  359.       handle_multiw(im, val);
  360.       return;
  361.       }
  362.  
  363.  
  364.     /* take care of overdraw */
  365.     if (rubber_on_screen(&rwin, &col))
  366.       {
  367.       set_current_window(rwin);
  368.       rubber_hide();
  369.       rubber_show(col);
  370.       }
  371.  
  372.     do_redraw(im);
  373.  
  374.  
  375.     if (double_buf)
  376.       {
  377.       set_current_window(win_id);
  378.       swapbuffers();
  379.       do_redraw(im);
  380.       }
  381.  
  382.     /* reset dirty rectangles */
  383.     ndrect = 0;
  384.  
  385.     set_current_window(owin);
  386. }
  387.  
  388.  
  389. /*********************************************************************
  390.  * redraw a rectangular region on screen. The region is not necessarily
  391.  * within the image.
  392.  *
  393.  * The input location is relative to Window
  394.  ********************************************************************/
  395. void
  396. img_rect_redraw(IPTR img, int x, int y, int w, int h)
  397. {
  398.     const Rect_t *wr, *ir, *cr, *ur;
  399.     long owin = winget();
  400.  
  401.     set_current_window(win_id);
  402.     drawmode(NORMALDRAW);
  403.     remap_main_window();
  404.  
  405.     if (!img->ok)
  406.       {
  407.       clear_screen(win_id, 0);
  408.       return;
  409.       }
  410.  
  411.     ir = img_rect(img);
  412.     wr = make_rect(0, 0, win_w - 1, win_h - 1);
  413.     cr = make_rect(x, y, w, h);
  414.  
  415.     /* if the region is outside the window, ignore it */
  416.     if (!union_rect(cr, wr))
  417.     return;
  418.  
  419.     /* completely within the image */
  420.     if (cover_rect(ir, cr))
  421.       {
  422.       draw_subimage(img, x, y, w, h);
  423.       }
  424.  
  425.     /* completely outside the image */
  426.     else if (!(ur = union_rect(ir, cr)))
  427.       {
  428.       rect_clear(win_id, x, x + w - 1, y, y + h - 1);
  429.       }
  430.  
  431.     /* larger than the image */
  432.     else if (cover_rect(cr, ir))
  433.       {
  434.       img->io->display(img, -1, 1);
  435.       }
  436.  
  437.     else
  438.       {
  439.       M_info("ImgRectRedraw", "mixed region");
  440.       clear_between_rect(ur, cr);
  441.       draw_subimage(img, ur->x, ur->y, ur->w, ur->h);
  442.       }
  443.  
  444.     set_current_window(owin);
  445. }
  446.  
  447. /*********************************************************************
  448.  * Convenience function to take care of double buffering
  449.  *********************************************************************/
  450. void
  451. dbl_rect_redraw(IPTR im, int x, int y, int w, int h)
  452. {
  453.     long owin = winget();
  454.  
  455.     img_rect_redraw(im, x, y, w, h);
  456.  
  457. #ifndef SGL_BUF
  458.     if (double_buf)
  459.       {
  460.       set_current_window(win_id);
  461.       swapbuffers();
  462.       img_rect_redraw(im, x, y, w, h);
  463.       }
  464. #endif
  465.  
  466.     set_current_window(owin);
  467. }
  468.  
  469. /*******************************************************
  470.  * do a subimage. Completely within the image.
  471.  *******************************************************/
  472. void
  473. draw_subimage(IPTR img, int x, int y, int w, int h)
  474. {
  475.     register int j, yi = img->yi;
  476.     register void **pp, *p;
  477.     long owin = winget();
  478.  
  479.     set_current_window(win_id);
  480.     remap_main_window();
  481.  
  482.     set_mem_warn(0);
  483.  
  484.     if ((pp = get_subimage(img, x, y, w, h)))
  485.       {
  486.       /* should'nt use Rectwrite, which swaps buffers is doublebuf */
  487.       PI_rectwrite(x, y, x + w - 1, y + h - 1, pp[0]);
  488.       free_mat(pp);
  489.       }
  490.     else
  491.       {
  492.       pp = img->mraster;
  493.       for (j = 0; j < h; j++)
  494.         {
  495.         p = (char *) pp[y - yi + j] + (x * img->esize);
  496.         PI_rectwrite(x, y + j, x + w - 1, y + j, p);
  497.         }
  498.       }
  499.  
  500.     set_mem_warn(1);
  501.  
  502.     set_current_window(owin);
  503. }
  504.  
  505. /***************************************************************
  506.  * cleans up everything
  507.  ************************************************************/
  508. void
  509. clean_up(void)
  510. {
  511.     if (win_id <= 0)
  512.       {
  513.       set_sysmap(1);    /* restore system clormap */
  514.       exit(1);
  515.       }
  516.  
  517.     reset_mouse_bounds();
  518.     set_current_window(win_id);
  519.     reshapeviewport();
  520.     clear_over_pup();
  521.     drawmode(NORMALDRAW);
  522.     clear_screen(win_id, 1);
  523.     set_sysmap(1);
  524.     gflush();
  525.     fl_check_forms();
  526.     winclose(win_id);
  527.     win_id = -1;
  528.  
  529. #ifdef M_DBG
  530.  
  531.     /*
  532.      * free all known memory allocated and see if there is any leaks. Need to
  533.      * do this only memory debug is on
  534.      */
  535.  
  536.     /* img_freemem(imgptr); */
  537.     free_all_ext_filter();
  538.     free_all_ext_convolv();
  539.  
  540.     cleanup_files();
  541.     cleanup_cut_paste();
  542.     free_all_actions();
  543.     free_all_options();
  544.     del_text();
  545.     free_all_ibrowsers();
  546.     mem_stat();
  547. #endif
  548.  
  549.     remove_clock_mailbox();
  550.     del_all_tmpf();
  551.     process_clean_up();
  552.     gexit();
  553.     exit(0);
  554. }
  555.  
  556. /******************************************************************
  557.  * invoked by repaint button from InfoPanel or others, but
  558.  * it is guaranteed that window size has not changed.
  559.  *****************************************************************/
  560. int
  561. do_repaint(IPTR im)
  562. {
  563.     long rwin;
  564.     int rcol;
  565.  
  566.  
  567.     remap_main_window();
  568.     clear_over_pup();
  569.  
  570.     set_current_window(win_id);
  571.     drawmode(NORMALDRAW);
  572.  
  573.     if (im && im->ok)
  574.       {
  575.       display_image(im, -1, 1);
  576.       handle_wm_other(im);
  577.       if (im->io->display != display_image)
  578.         {
  579.         display_sgf(im);
  580.         display_text(im);
  581.         }
  582.  
  583.       if (double_buf)
  584.         {
  585.         swapbuffers();
  586.         display_image(im, -1, 1);
  587.         display_sgf(im);
  588.         display_text(im);
  589.         }
  590.       }
  591.     else
  592.       {
  593.       clear_screen(win_id, 1);
  594.       }
  595.  
  596.  
  597.     if (rubber_on_screen(&rwin, &rcol))
  598.       {
  599.       set_current_window(rwin);
  600.       rubber_show(rcol);
  601.       }
  602.  
  603.     /* clean up dirty rectangles and all events */
  604.     ndrect = 0;
  605.     fl_qreset();
  606.     drawmode(NORMALDRAW);
  607.     return 0;
  608. }
  609.  
  610.  
  611. /**********************************************************************
  612.  * Wrappers for FORMS library. This is necessary because this is
  613.  * the only way we can get hold of the dirty rectangles left behind
  614.  * by closing of FORMS
  615.  *
  616.  **********************************************************************/
  617.  
  618. #define MAX_F    10        /* maximum no. of forms on screen  */
  619. #define BORDER_P 12        /* to clean up the border pixels   */
  620.  
  621. /* Wrapper structure */
  622. typedef struct fw_t
  623. {
  624.     const char *name;        /* name           */
  625.     FL_FORM *f;            /* The forms      */
  626.     int x, y, w, h;        /* dimension      */
  627.     int b;            /* if has a border */
  628.     int iconified;
  629. }
  630. Fw_t;
  631.  
  632. static Fw_t forms[MAX_F];
  633.  
  634. /************************************************************
  635.  * Find next available slot for a new form
  636.  ***********************************************************/
  637. static Fw_t *
  638. next_fw(void)
  639. {
  640.     register Fw_t *fi = forms, *ff = fi + MAX_F;
  641.  
  642.     /* must not overwrite the iconified stuff */
  643.     while (--ff >= fi && ff->f && (ff->f->visible || ff->iconified))
  644.     ;
  645.  
  646.     if (ff < fi)        /* not found */
  647.       {
  648.       M_err("NextFW", "Out of bounds");
  649.       clean_up();
  650.       }
  651.     return ff;
  652. }
  653.  
  654. /****************************************************************
  655.  * update form location
  656.  **************************************************************/
  657. static void
  658. update_fw(Fw_t * fw)
  659. {
  660.     FL_FORM *f = fw->f;
  661.  
  662.     fw->x = f->x;
  663.     fw->y = f->y;
  664.     fw->w = (f->w + 0.1);
  665.     fw->h = (f->h + 0.1);
  666. }
  667.  
  668. /************************************************************
  669.  * Convert a form dimension to the screen pixel size with border
  670.  * size figureed in and add it to the dirty rectangle pool
  671.  ************************************************************/
  672.  
  673. static void
  674. fw_to_drect(Fw_t * fw)
  675. {
  676.     int b = fw->b ? 12 : 1;    /* border factors */
  677.  
  678.     add_d_rect(fw->x - b, fw->y - b, (fw->w + 2 * b), (fw->h + 4 * b));
  679. }
  680.  
  681. /***************************************************************
  682.  * A new form becomes visible, record its location and dimension
  683.  **************************************************************/
  684. static void
  685. add_new_fw(FL_FORM * f, int border, const char *name)
  686. {
  687.     Fw_t *fw = next_fw();
  688.  
  689.     fw->f = f;
  690.     fw->x = f->x;
  691.     fw->y = f->y;
  692.     fw->w = (f->w + 0.1);
  693.     fw->h = (f->h + 0.1);
  694.     fw->b = border;
  695.     fw->name = name;
  696. }
  697.  
  698. /*****************************************************************
  699.  * check if a given window ID is a valid one. A valid window ID is
  700.  * defined to be the ID of a window that is currently on screen
  701.  *****************************************************************/
  702. int
  703. is_valid_win(long win)
  704. {
  705.     register int valid = 0;
  706.     register Fw_t *fw = forms + MAX_F;
  707.  
  708.     if (win < 0 || win == 256)
  709.     return 0;
  710.  
  711.     while (--fw >= forms && !valid)
  712.     valid = (fw->f && fw->f->window == win && fw->f->visible);
  713.     return (valid || win == win_id);
  714. }
  715.  
  716.  
  717. /***********************************************************************
  718.  * High level cursor routines
  719.  *
  720.  * Since we need to set all windows to a particular, it is not
  721.  * possible to move the cursor routine to other modules without
  722.  * introduce major ugliness
  723.  ***********************************************************************/
  724.  
  725.  
  726. /*****************************************************************
  727.  * show an hour glass cursor to indicate a brief  busy
  728.  *****************************************************************/
  729. static int lastbusy;        /* set if text is shown */
  730.  
  731. void
  732. show_busy(const char *s)
  733. {
  734.     long owin = winget();
  735.     Fw_t *fw = forms + MAX_F;
  736.  
  737.     /* set all valid window to busy cursor */
  738.     while (--fw >= forms)
  739.       {
  740.       if (fw->f && fw->f->visible)
  741.           set_cursor(fw->f->window, CUR_BUSY);
  742.       }
  743.  
  744.     /* also show the string if requested */
  745.     if (s && *s)
  746.       {
  747.       show_misc_info2(s);
  748.       lastbusy = 1;
  749.       }
  750.  
  751.     set_cursor(win_id, CUR_BUSY);
  752.  
  753.     set_current_window(owin);
  754. }
  755.  
  756. /***************************************************************
  757.  * Restore the default curosr for all windows. Note the default
  758.  * cursor for a particular window does not have to be the system
  759.  * default.
  760.  ***************************************************************/
  761. static void
  762. reset_all_cursor(void)
  763. {
  764.     Fw_t *fw = forms + MAX_F;
  765.  
  766.     reset_cursor(win_id);
  767.     while (--fw >= forms)
  768.       {
  769.       if (fw->f && fw->f->window > 0)
  770.           reset_cursor(fw->f->window);
  771.       }
  772. }
  773.  
  774. /**************************************************************
  775.  * Turn off hourglass class cursor and hide info reporting box
  776.  **************************************************************/
  777. void
  778. end_busy(void)
  779. {
  780.     long owin = winget();
  781.  
  782.     /* Always a good idea to check GL Q events after busy */
  783.     check_emergency();
  784.  
  785.     reset_all_cursor();
  786.  
  787.     /* multiple hides looks bad in single buffer mode */
  788.     if (lastbusy)
  789.       {
  790.       hide_misc_info2();
  791.       lastbusy = 0;
  792.       }
  793.  
  794.     set_current_window(owin);
  795. }
  796.  
  797. /******************************************************************
  798.  * show 4 different cursors in succession to give an appearance
  799.  * of rotating. Only does Control, InfoPanel, Main and current
  800.  * window
  801.  ******************************************************************/
  802. void
  803. rotate_cursor(void)
  804. {
  805.     long owin = winget(), twin;
  806.     int curindex;
  807.  
  808.     if (win_id < 0)
  809.     return;
  810.  
  811.     curindex = rotate_circle_cursor(win_id);
  812.  
  813.     if ((twin = get_control_wid()) > 0)
  814.     set_cursor(twin, curindex);
  815.     if ((twin = get_info_wid()) > 0)
  816.     set_cursor(twin, curindex);
  817.     if (owin > 0)
  818.     set_cursor(owin, curindex);
  819. }
  820.  
  821. /*********************************************************/
  822. void
  823. remove_rotate_cursor(void)
  824. {
  825.     reset_all_cursor();
  826. }
  827.  
  828. /**********************************************************
  829.  * Show form guarantees the new form will be active
  830.  *********************************************************/
  831. long
  832. bit_show_form(FL_FORM * f, int where, int border, const char *s)
  833. {
  834.     int gborder = (always_border && border >= 0) || border > 0;
  835.     long win = f->window;
  836.  
  837.     if (f->visible)
  838.       {
  839.       fl_activate_form(f);
  840.       f->frozen = 0;
  841.       set_current_window(win);
  842.       }
  843.     else
  844.       {
  845.       win = fl_show_form(f, where, gborder, s);
  846.       add_new_fw(f, gborder, s);
  847.       }
  848.     return win;
  849. }
  850.  
  851. /**********************************************************
  852.  * Close a form. Record the position only if overlap with the
  853.  * main window (checked in add_d_rect), even so, we still running
  854.  * the danger that we might've recorded too many dirty rectangles
  855.  * that are  on top of another form.
  856.  **********************************************************/
  857. void
  858. bit_hide_form(register FL_FORM * f)
  859. {
  860.     register Fw_t *fw = forms + MAX_F;
  861.     short val;
  862.  
  863.     if (!f || !f->visible)
  864.     return;
  865.  
  866.     /* search for it */
  867.     while (--fw >= forms && fw->f != f)
  868.     ;
  869.  
  870.     if (fw < forms)        /* not found */
  871.       {
  872.       Bark("HideForm", "Something is wrong");
  873.       return;
  874.       }
  875.  
  876.     /* record total size in dirty rectangle pool */
  877.  
  878.     update_fw(fw);
  879.     fl_hide_form(f);        /* hide it */
  880.     fw_to_drect(fw);
  881.  
  882.     fw->f = 0;            /* reset wrapper */
  883.  
  884.     /* the following will make interaction appear faster */
  885.     (void) fl_check_forms();
  886.     if (fl_qtest() == REDRAW && fl_qread(&val) == REDRAW)
  887.       {
  888.       repaint(imgptr, val);
  889.       /*
  890.        * slide show depends on a Q event to break the fl_qread block,
  891.        * since we eat the REDRAW, generate another
  892.        */
  893.       fl_qenter(REDRAW, 0);
  894.       }
  895. }
  896.  
  897. /***** check if a rectagle overlaps with the main window ****/
  898. static int
  899. overlap(int x, int y, int w, int h)
  900. {
  901.     int xi, yi, xf, yf;
  902.  
  903.     xi = Max(x, win_xo);
  904.     yi = Max(y, win_yo);
  905.     xf = Min(x + w - 1, win_xo + win_w - 1);
  906.     yf = Min(y + h - 1, win_yo + win_h - 1);
  907.     return (xf > xi && yf > yi);
  908. }
  909.  
  910. static int
  911. moved(Fw_t * fw, FL_FORM * f)
  912. {
  913.     return ((fw->x - f->x) || (fw->y - f->y) ||
  914.         (fw->w - (int) (f->w + 0.1)) ||
  915.         (fw->h - (int) (f->h + 0.1)));
  916. }
  917.  
  918. /*********************************************************************
  919.  * Upon receiving a redraw event, check to see if any of the visible
  920.  * forms has moved.
  921.  * TODO: might want to check the window stack to see any window is pushed
  922.  * out of sight ?????????
  923.  *********************************************************************/
  924. void
  925. gather_dirty_region(void)
  926. {
  927.     register FL_FORM *f;
  928.     register Fw_t *fw = forms + MAX_F;
  929.  
  930.     /*
  931.      * loop thru all forms and checking each to see if any of the forms has
  932.      * been moved/resized etc
  933.      */
  934.  
  935.     while (--fw >= forms)
  936.       {
  937.       /* if no long visible, ignore it */
  938.       if (!((f = fw->f) && f->visible))
  939.           continue;
  940.  
  941.       /*
  942.        * if havnt moved or moved but both new and old positions are
  943.        * outside the windows
  944.        */
  945.  
  946.       if (!moved(fw, f))
  947.           continue;
  948.  
  949.       /* moved, but completely outside window */
  950.       if (!overlap(f->x, f->y, f->w, f->h) &&
  951.           !overlap(fw->x, fw->y, fw->w, fw->h))
  952.           continue;
  953.  
  954.  
  955.       /*
  956.        * fw->f is the current form and its (x,y,w,h) is the current
  957.        * location. fw->{x,y,w,h} is the last location
  958.        */
  959.  
  960.       /*
  961.        * if any form was completely outside of the window, that means we
  962.        * have a bad location(first move in may not be registered, this
  963.        * fw->x is bad). However, if current location is outside as well,
  964.        * ignore it
  965.        */
  966.  
  967.       if (!overlap(fw->x, fw->y, fw->w, fw->h))
  968.  
  969.         {
  970.         /*
  971.          * might be a good idea to reset region to zero and skip the
  972.          * checking altogether ???
  973.          */
  974.         fw->x = win_xo;
  975.         fw->y = win_yo;
  976.         fw->w = win_w;
  977.         fw->h = win_h;
  978.         }
  979.       fw_to_drect(fw);
  980.  
  981.       /* update  location */
  982.       update_fw(fw);
  983.       }
  984. }
  985.  
  986. /*************************************************************
  987.  * Iconify everything, including all forms (actually closing)
  988.  ************************************************************/
  989.  
  990. static IPTR imicon;        /* the iconic image */
  991.  
  992. /***********************************************************
  993.  * WINICONIREDRAW event handler
  994.  **********************************************************/
  995. void
  996. bit_draw_icon(int val)
  997. {
  998.     static int badiconfile;
  999.     const char *icon_file = "touchup.icon";
  1000.  
  1001.     /* only bitch once */
  1002.     if (!imicon && !badiconfile &&
  1003.     !(imicon = load_image(get_HELPFile(icon_file))))
  1004.       {
  1005.       Bark("IconLoad", "Bad icon file %s", get_HELPFile(icon_file));
  1006.       badiconfile = 1;
  1007.       }
  1008.  
  1009.     /*
  1010.      * draw it. Always do it in RGBmode so that we can restore the default
  1011.      * system colormap
  1012.      */
  1013.  
  1014.     if (imicon)
  1015.     img_convert_type(imicon, T_RGBA);
  1016.  
  1017.     remap_main_window();
  1018.     set_current_window(val);
  1019.     set_rgb_mode();
  1020.  
  1021.     if (imicon && imicon->ok)
  1022.       {
  1023.       lrectwrite(1, 1, imicon->w, imicon->h, imicon->raster);
  1024.       }
  1025.     else
  1026.       {
  1027.       /* this is the best we can do */
  1028.       cpack(0x00808080);
  1029.       clear();
  1030.       cpack(0);
  1031.       cmov2i(40, 40);
  1032.       charstr("Bit");
  1033.       }
  1034.  
  1035.     if (double_buf)
  1036.       {
  1037.       swapbuffers();
  1038.       lrectwrite(1, 1, imicon->w, imicon->h, imicon->raster);
  1039.       }
  1040. }
  1041.  
  1042. /*************************************************************
  1043.  * WINFREEZE event handler: Iconify all windows
  1044.  *************************************************************/
  1045. void
  1046. bit_iconify(void)
  1047. {
  1048.     Fw_t *fw = forms + MAX_F;
  1049.  
  1050.     remove_clock_mailbox();
  1051.     clear_over_pup();
  1052.  
  1053.     pewin_iconify();
  1054.  
  1055.     /* close all forms and make a note of it */
  1056.     while (--fw >= forms)
  1057.       {
  1058.       if (fw->f && fw->f->visible)
  1059.         {
  1060.         fw->iconified = 1;
  1061.         fl_hide_form(fw->f);
  1062.         }
  1063.       }
  1064.  
  1065.     set_sysmap(0);
  1066.     ndrect = 0;
  1067. }
  1068.  
  1069. /*************************************************************
  1070.  * When WINTHAW is received, do this: De-iconify all windows
  1071.  **************************************************************/
  1072. void
  1073. bit_de_iconify(void)
  1074. {
  1075.     Fw_t *fw = forms + MAX_F;
  1076.  
  1077.     show_clock_mailbox(-1, -1, 0, 0);
  1078.  
  1079.     remove_progress_report();
  1080.     update_image_info(imgptr);
  1081.  
  1082.     pewin_de_iconify();
  1083.  
  1084.     /* bring back all closed forms */
  1085.     while (--fw >= forms)
  1086.       {
  1087.       if (fw->iconified && fw->f)
  1088.         {
  1089.         fw->iconified = 0;
  1090.         fl_show_form(fw->f, FL_PLACE_POSITION, fw->b, fw->name);
  1091.         }
  1092.       }
  1093.  
  1094.     remap_main_window();
  1095.     ndrect = 0;            /* so that we do a full redraw */
  1096. }
  1097.  
  1098. /*******************************************************************
  1099.  * Try to lessen the impact of winset
  1100.  *******************************************************************/
  1101.  
  1102. void
  1103. set_current_window(long wid)
  1104. {
  1105.     if (wid > 0 && winget() != wid)
  1106.     winset(wid);
  1107. }
  1108.